## @package Canvas  
# Darryl Wallace - 2010 darryl@wallynet.ca or wallacdj@gmail.com
# This file is used for prototyping..

from PyQt4 import QtCore, QtGui

from PyQt4.QtCore import QPoint, QString, QRect, QStringList
from PyQt4.QtGui import QImage, QPainter, QWidget, QPainterPath
from PyQt4.QtGui import *

## Create a Layer object that is based on the "paint area" of the plug'n'paint example
## Each layer will act as a container for painting.   

class CanvasTool(QtGui.QGraphicsItem):
    DRAWING, ERASER, SELECTION, UNDEFINED=range(4) #tool type
    def __init__(self, parent=None):
        QtGui.QGraphicsItem.__init__(self, parent)
        self.pen=QtGui.QPen()
        self.brush=QtGui.QBrush()
    #__init_
    
    def type(self):
        return CanvasTool.UNDEFINED
    #type
   
    def setPen(self, pen):
        self.pen=QPen(pen)
    #setPen
        
    def setBrush(self, brush):
        self.brush=QBrush(brush)
    #setBrush
        
    def paint(self, painter, styleOption, widget=None):
        raise NotImplementedError, "This feature is not implemented."
    #paint
    
    def handleMousePressEvent(self, e):
        assert(isinstance(e, QtGui.QGraphicsSceneEvent))
        raise NotImplementedError, "This feature is not implemented."
        
    def handleMouseMoveEvent(self, e):
        assert(isinstance(e, QtGui.QGraphicsSceneEvent))
        raise NotImplementedError, "This feature is not implemented."
    #handleMouseMoveEvent
    
    def boundingRect(self):
        assert(isinstance(e, QtGui.QGraphicsSceneEvent))
        raise NotImplementedError, "This feature is not implemented."
    #boundingRect
#CanvasItem

class CanvasRectItem(CanvasTool):
    def __init__(self, parent=None):
        CanvasItem.__init__(self, parent)
        self.initalPos=None
        self.currentPos=None
    def type(self):
        return CanvasTool.DRAWING
    #type
    def boundingRect(self):
        x0=self.initialPos.x()
        y0=self.initialPos.y()
        x1=self.currentPos.x()
        y1=self.currentPos.y()
        x=x0
        width=x1-x0
        y=y0
        height=y1-y0
        if x1<x0:
            x=x1
            width=x0-x1
        if y1<y0:
            y=y1
            height=y0-y1
        
        penWidth=self.pen.width()
        return QtCore.QRectF(x-penWidth/2, y-penWidth/2, width+penWidth, height+penWidth)
    #boundingRect
    def handleMousePressEvent(self, e):
        self.initialPos=e.scenePos()
        self.currentPos=e.scenePos()
    #handleMousePressEvent()
    def handleMouseMoveEvent(self, e):
        self.currentPos=e.scenePos()
        self.scene().invalidate()
    #handleMouseMoveEvent
    def paint(self, painter, styleOption, widget=None):
        painter.setPen(self.pen)
        painter.setBrush(self.brush)
        painter.drawRect(self.boundingRect())
    #paint
#CanvasRectItem

class CanvasStarItem(CanvasTool):
    def __init__(self, parent=None):
        CanvasItem.__init__(self, parent)
        self.initialPos=None
        self.currentPos=None
    #__init__
    def type(self):
        return CanvasTool.DRAWING
    #type
    def boundingRect(self):
        x0=self.initialPos.x()
        y0=self.initialPos.y()
        x1=self.currentPos.x()
        y1=self.currentPos.y()
        x=x0
        width=x1-x0
        y=y0
        height=y1-y0
        if x1<x0:
            x=x1
            width=x0-x1
        if y1<y0:
            y=y1
            height=y0-y1
        
        penWidth=self.pen.width()
        return QtCore.QRectF(x-penWidth/2, y-penWidth/2, width+penWidth, height+penWidth)
    #boundingRect
    def handleMousePressEvent(self, e):
        self.initialPos=e.scenePos()
        self.currentPos=e.scenePos()
    #handleMousePressEvent()
    def handleMouseMoveEvent(self, e):
        self.currentPos=e.scenePos()
        self.scene().invalidate()
    #handleMouseMoveEvent
    def paint(self, painter, styleOption, widget=None):
        painter.setPen(self.pen)
        painter.setBrush(self.brush)
        r=self.boundingRect()
        path=QPainterPath()
        x0=r.x()
        y0=r.y()
        width=r.width()
        height=r.height()
        path.moveTo(x0+width/2, y0)
        path.lineTo(x0, y0+height)
        path.lineTo(x0+width, y0+height/3)
        path.lineTo(x0, y0+height/3)
        path.lineTo(x0+width, y0+height)
        path.lineTo(x0+width/2, y0)
        painter.drawPath(path)
    #paint
#CanvasStarItem

class CanvasPenItem(CanvasTool):
    def __init__(self, parent=None):
        CanvasTool.__init__(self, parent)
        self.initialPos=None
        self.currentPos=None
        self.lastPos=None
        self.br=QtCore.QRectF()
        self.painterPath=QtGui.QPainterPath()
    #__init__
    def type(self):
        return CanvasTool.DRAWING
    #type
    def boundingRect(self):
        halfpw=self.pen.width()/2
        return self.br.adjusted(-halfpw, -halfpw, halfpw, halfpw)
    #boundingRect
    def handleMousePressEvent(self, e):
        self.initialPos=e.scenePos()
        self.lastPos=e.scenePos();
        self.currentPos=e.scenePos()
        self.painterPath.moveTo(self.currentPos)
        self.br=QtCore.QRectF(self.currentPos.x(), self.currentPos.y(), 0, 0)
        
    #handleMousePressEvent()
    def handleMouseMoveEvent(self, e):
        self.lastPos=self.currentPos
        self.currentPos=e.scenePos()
        dx1=self.currentPos.x()-self.br.x()
        dy1=self.currentPos.y()-self.br.y()
        dx2=self.currentPos.x()-self.br.right()
        dy2=self.currentPos.y()-self.br.bottom()
        if dx1>0:
            dx1=0.0
        if dy1>0:
            dy1=0.0;
        if dx2<0:
            dx2=0.0
        if dy2<0:
            dy2=0.0
        self.br.adjust(dx1, dy1, dx2, dy2)
        self.scene().invalidate()
    #handleMouseMoveEvent
    def paint(self, painter, styleOption, widget=None):
        painter.setPen(self.pen)
        painter.setBrush(self.brush)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        self.painterPath.lineTo(self.currentPos)
        painter.drawPath(self.painterPath)
    #paint
#CanvasPenItem

class CanvasRoundEraser(CanvasTool):
    def __init__(self, parent=None):
        CanvasTool.__init__(self, parent)
        self.initialPos=None
        self.currentPos=None
        self.lastPos=None
        self.br=QtCore.QRectF()
        self.painterPath=QtGui.QPainterPath()
        self.pen=QPen()
        color=QtGui.QColor(10, 255, 210, 0)
        self.pen.setColor(color)
        self.brush=QBrush()
        self.brush.setColor(color)
        self.pen.setWidth(2)
    #__init__
    def type(self):
        return CanvasTool.ERASER
    #type
    def boundingRect(self):
        halfpw=self.pen.width()/2
        return self.br.adjusted(-halfpw, -halfpw, halfpw, halfpw)
    #boundingRect
    def handleMousePressEvent(self, e):
        self.initialPos=e.scenePos()
        self.lastPos=e.scenePos();
        self.currentPos=e.scenePos()
        self.br=QtCore.QRectF(self.currentPos.x(), self.currentPos.y(), 0, 0)
        
        p=QPainter(self.parentItem().layerImage)
        p.setPen(self.pen)
        p.setBrush(self.brush)
        p.drawEllipse(self.currentPos.x(), self.currentPos.y(), 10, 10)
        self.scene().invalidate()
        
    #handleMousePressEvent()
    def handleMouseMoveEvent(self, e):
        self.currentPos=e.scenePos()
        p=QPainter(self.parentItem().layerImage)
        p.setPen(self.pen)
        p.setBrush(self.brush)
        p.drawEllipse(self.currentPos.x(), self.currentPos.y(), 10, 10)
        self.scene().invalidate()
    #handleMouseMoveEvent
    def paint(self, painter, styleOption, widget=None):
        pass
    #paint
#CanvasEraserTool
        
## Port of the Paint Area from the PlugAndPaint example
class PaintArea(QtGui.QWidget):
    ## ANCHORS
    TOP_LEFT, TOP, TOP_RIGHT, LEFT, MIDDLE, RIGHT, BOTTOM_LEFT, BOTTOM, BOTTOM_RIGHT=range(9)
    def __init__(self, width, height, parent=None):
        QtGui.QWidget.__init__(self, parent)
        
        self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)
        self.setAttribute(QtCore.Qt.WA_StaticContents)
        #self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        
        ## Internal attributes
        self.theImage=QtGui.QImage(width, height, QtGui.QImage.Format_ARGB32)
        self.antialiasing=True
        self.color=QtGui.QColor()
        self.pendingPath=QtGui.QPainterPath()
        self.brush=QtGui.QBrush()
        self.brushInterface=None
        self.lastPos=QtCore.QPoint()       
        
    #__init__
    
    def fillImage(self, color=None):
        assert(isinstance(color, QtGui.QColor))
        self.theImage.fill(color.rgb())
    #fillImage
    
    ## scale the image to these the new pixel width,height
    def resizeImage(self, width, height):
        pass
    #resizeImage
    def resizeCanvas(self, width, height, anchor):
        pass
    #resizeCanvas
    def setAntiAliasing(self, aa):
        assert(isinstance(aa, bool))
        
        self.antialiasing=aa
    #setAntiAliasing
    def setImage(self, image):
        assert(isinstance(image, QtGui.QImage))
        self.theImage=image
    #setImage
    
    def insertShape(self, path):
        assert(isinstance(path, QtGui, QPainterPath))
    #insertShape
    
    def setBrushColor(self, color):
        assert(isinstance(color, QtGui.QColor))
        self.color=color
    #setBrushColor
    
    def setBrushWidth(self, width):
        self.thickness=width
    #setBrushWidth
    
    def setBrush(self, brushInterface, brush):
        self.brushInterface=brushInterface
        self.brush=brush
    #setBrush
    
    def sizeHint(self):
        return self.theImage.size()
    #sizeHint
    
    def paintEvent(self, event):
        painter=QtGui.QPainter(self)
        painter.drawImage(QtCore.QPoint(0, 0), self.theImage)
    #paintEvent
    
    def mousePressEvent(self, event):
        if event.button()==QtCore.Qt.LeftButton:
            if not self.pendingPath.isEmpty():
                painter=QtGui.QPainter(self.theImage)
                self.setupPainter(painter)
                
                boundingRect=self.pendingPath.boundingRect()
                gradient=QtGui.QLinearGradient(boundingRect.topRight(), boundingRect.bottomLeft())
                gradient.setColorAt(0.0, QtGui.QColor(self.color.red(), self.color.green(), 
                                                      self.color.blue(), 63))
                gradient.setColorAt(1.0, QtGui.QColor(self.color.red(), self.color.green(), 
                                                      self.color.blue(), 191))
                painter.setBrush(gradient)
                painter.translate(event.pos()-boundingRect.center())
                painter.drawPath(self.pendingPath)
                
                self.pendingPath=QtGui.QPainterPath()
                
                self.unsetCursor()
                
                self.update()
            else:
                if self.brushInterface is not None:
                    painter=QtGui.QPainter(self.theImage)
                    self.setupPainter(painter)
                    rect=self.brushInterface.mousePress(self.brush, painter, event.pos())
                    
                    self.update(rect)
                self.lastPos=event.pos()
    #mousePressEvent
    
    def mouseMoveEvent(self, event):
        if (event.buttons() & QtCore.Qt.LeftButton) and self.lastPos !=QtCore.QPoint(-1, -1):
            
            if self.brushInterface:
                painter=QtGui.QPainter(self.theImage)
                self.setupPainter(painter)
                rect=self.brushInterface.mouseMove(self.brush, painter, self.lastPos, event.pos())
                
                tempImage=self.theImage.copy(rect)
                
                self.update(rect)
            self.lastPos=event.pos()
    #mouseMoveEvent
    
    def mouseReleaseEvent(self, event):
        if (event.buttons() & QtCore.Qt.LeftButton) and lastPos !=QtCore.QPoint(-1, -1):
            
            if self.brushInterface:
                painter=QtGui.QPainter(self.theImage)
                self.setupPainter(painter)
                rect=self.brushInterface.mouseRelease(self.brush, painter, event.pos())
            
                self.update(rect)
                
                
                
            self.lastPos=QtCore.QPoint(-1, -1)
#    #mouseReleaseEvent
    
    def setupPainter(self, painter):
        painter.setRenderHint(QtGui.QPainter.Antialiasing, self.antialiasing)
        painter.setPen(QtGui.QPen(self.color, self.thickness, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
    #setupPainter
    
    def getImage(self):
        return self.theImage
#PaintArea   

## Canvas is the main object where drawing takes place.
# it handles the layers and the main background scene.
class Canvas(QtGui.QGraphicsScene):
    def __init__(self, parent=None):
        QtGui.QGraphicsScene.__init__(self)
        
        gridSize = 10
        backgroundPixmap = QtGui.QPixmap(gridSize*2, gridSize*2)
        backgroundPixmap.fill(QtGui.QColor("white"))
        painter = QtGui.QPainter(backgroundPixmap)
        backgroundColor = QtGui.QColor("gray")
        painter.fillRect(0, 0, gridSize, gridSize, backgroundColor)
        painter.fillRect(gridSize, gridSize, gridSize, gridSize, backgroundColor)
        painter.end()
        
        self.setBackgroundBrush(QBrush(QtGui.QColor("lightgray")))
        
        # default Canvas background will be 500x500
        p=QPen(QtGui.QColor("black"))
        p.setWidth(1)
        p.setJoinStyle(QtCore.Qt.MiterJoin)
        
        self.backgroundLayer = self.addRect(0, 0, 500, 500, p, QBrush(backgroundPixmap))
        self.backgroundLayer.setZValue(0)
        self.layers=[]
        
        self.currentBrush=QtGui.QBrush()
        self.currentPen=QtGui.QPen()
        self.currentPen.setJoinStyle(QtCore.Qt.MiterJoin)
        
        self.currentShape="rect"
    #__init__
    
    def addLayer(self):
        self.layers.append(Layer(self.backgroundLayer))
        self.currentLayer=self.layers[-1]
        self.currentLayerIndex=len(self.layers)-1
        self.layers[-1].setZValue(self.currentLayerIndex*10)
    def deleteLayer(self, index):
        if index>len(self.layers):
            raise IndexError, "The layer index does not exist."
        ## The current index will remain the same
        self.layers.pop(index)
        if len(self.layers)==0:
            self.addLayer()
            self.currentIndex=0
        if self.currentIndex>len(self.layers):
            self.currentIndex=len(self.layers)-1
        
        
    def setCurrentLayer(self, index):
        if index>len(self.layers):
            raise IndexError, "The layer index does not exist."
        self.currentLayer=self.layers[index]
        self.currentLayerIndex=index
        
    def setBrushColor(self, color):
        self.currentBrush.setColor(color)
    
    def setPenColor(self, color ):
        self.currentPen.setColor(color)
    
    def setPenWidth(self, width):
        self.currentPen.setWidth(width)
        
    def mouseDoubleClickEvent(self, e):
        QtGui.QGraphicsScene.mouseDoubleClickEvent(self, e)
        self.currentItem = None
        
    def mousePressEvent(self, e):
        QtGui.QGraphicsScene.mousePressEvent(self, e)
        self.currentItem=CanvasPenItem(self.currentLayer)
        #self.currentItem.setPen(self.currentPen)
        #self.currentItem.setBrush(self.currentBrush)
        self.currentItem.handleMousePressEvent(e)
        
#        self.currentItem=QGraphicsRectItem(e.scenePos().x(), e.scenePos().y(), 1, 1)
#        self.currentItem.setPen(self.currentPen)
#        self.currentItem.setBrush(self.currentBrush)
#        #self.currentItem.setZValue(10*self.currentLayerIndex+1)
#        self.currentItem.setParentItem(self.currentLayer)
#        self.itemStartPos=e.scenePos()
     
        
    def mouseMoveEvent(self, e):
#        x0=self.currentItem.rect().x()
#        y0=self.currentItem.rect().y()
#        x1=self.currentItem.rect().width()+x0
#        y1=self.currentItem.rect().height()+y0
#        
#        ynew=e.scenePos().y()
#        xnew=e.scenePos().x()
#        xnew0=e.lastScenePos().x()
#        ynew0=e.lastScenePos().y()
##        if xnew-xnew0<0:
##            print "MOVING BACKWARDS IN X"
##            if xnew<self.itemStartPos.x():
##                x0=xnew
##                xnew=item.start
##                
##            
##        if ynew-ynew0<0:
##            print "MOVING BACKWARDS IN Y"
#        if xnew < self.itemStartPos.x():
#            x0=xnew
#            xnew=self.itemStartPos.x()
#        if ynew < self.itemStartPos.y():
#            y0=ynew
#            ynew=self.itemStartPos.y()
#            
#            
#        newWidth=xnew-x0
#        newHeight=ynew-y0
#        
#        self.currentItem.setRect(x0, y0, newWidth, newHeight)
        self.currentItem.handleMouseMoveEvent(e)
        QtGui.QGraphicsScene.mouseMoveEvent(self, e)
        
    def mouseReleaseEvent(self, e):
        if self.currentItem is not None:
            QtGui.QGraphicsScene.mouseReleaseEvent(self, e)
            self.currentLayer.addItem(self.currentItem)
            self.removeItem(self.currentItem)
            self.currentItem=None
            self.invalidate()
            
    def save(self, filename):
        output=QImage(self.width(), self.height(), QtGui.QImage.Format_ARGB32)
        p=QPainter();
        p.begin(output)
        for layer in self.layers:
            p.drawImage(0, 0, layer.layerImage)
        p.end()
        return output.save(filename)
        
        
        
        
class Layer(QtGui.QGraphicsItem):
    def __init__(self, parent=None):
        QtGui.QGraphicsItem.__init__(self, parent)
        
        
        if parent is not None:
            self.layerImage=QtGui.QImage(parent.rect().width(), parent.rect().height(), QtGui.QImage.Format_ARGB32)
        else:
            self.layerImage=QtGui.QImage(1, 1, QtGui.QImage.Format_ARGB32)
            
        #
    #__init__
            
    def boundingRect(self):
        imageSize=self.layerImage.size()
        return QtCore.QRectF(0, 0, imageSize.width(), imageSize.height())
    #boundingRect
    
    def getImage(self):
        return self.layerImage
    #getImage
        
    def resize(self, width, height, anchorLocation):
        self.layerImage.setWidth(width)
        self.layerImage.setHeight(height)
        
    #resize
    
    def fillImage(self, color):
        p=QPainter()
        p.begin(self.layerImage)
        p.fillRect(0, 0, self.layerImage.width(), self.layerImage.height(), QBrush(color))
        p.end()
        
    def paint(self, painter,  styleOption, widget):
        painter.drawImage(0, 0, self.layerImage)
        
    
    def addItem(self, item):
        p=QPainter()
        p.begin(self.layerImage)        
        styleoption=QtGui.QStyleOptionGraphicsItem()
        item.paint(p, styleoption)
        p.end()
    #addItem
#LayerItem
        
        
    
    

class ScrollZoomGraphicsView(QtGui.QGraphicsView):
    """|QGraphicsView| that can synchronize panning & zooming of multiple
    instances.

    Also adds support for various scrolling operations and mouse wheel
    zooming."""

    def __init__(self, scene=None, parent=None):
        """:param scene: initial |QGraphicsScene|
        :type scene: QGraphicsScene or None
        :param QWidget: parent widget
        :type QWidget: QWidget or None"""
        if scene:
            super(ScrollZoomGraphicsView, self).__init__(scene, parent)
        else:
            super(ScrollZoomGraphicsView, self).__init__(parent)

        self._handDrag = True #disable panning view by dragging
        self.clearTransformChanges()
        self.connectSbarSignals(self.scrollChanged)

    # ------------------------------------------------------------------

    #Signals

    transformChanged = QtCore.pyqtSignal()
    """Transformed Changed **Signal**.

    Emitted whenever the |QGraphicsView| Transform matrix has been
    changed."""
    
    scrollChanged = QtCore.pyqtSignal()
    """Scroll Changed **Signal**.

    Emitted whenever the scrollbar position or range has changed."""
    
    wheelNotches = QtCore.pyqtSignal(float)
    """Wheel Notches **Signal** (*float*).

    Emitted whenever the mouse wheel has been rolled. A wheelnotch is
    equal to wheel delta / 240"""
    
    def connectSbarSignals(self, slot):
        """Connect to scrollbar changed signals to synchronize panning.

        :param slot: slot to connect scrollbar signals to."""
        sbar = self.horizontalScrollBar()
        sbar.valueChanged.connect(slot, type=QtCore.Qt.UniqueConnection)
        #sbar.sliderMoved.connect(slot, type=QtCore.Qt.UniqueConnection)
        sbar.rangeChanged.connect(slot, type=QtCore.Qt.UniqueConnection)

        sbar = self.verticalScrollBar()
        sbar.valueChanged.connect(slot, type=QtCore.Qt.UniqueConnection)
        #sbar.sliderMoved.connect(slot, type=QtCore.Qt.UniqueConnection)
        sbar.rangeChanged.connect(slot, type=QtCore.Qt.UniqueConnection)

        #self.scrollChanged.connect(slot, type=QtCore.Qt.UniqueConnection)

    def disconnectSbarSignals(self):
        """Disconnect from scrollbar changed signals."""
        sbar = self.horizontalScrollBar()
        sbar.valueChanged.disconnect()
        #sbar.sliderMoved.disconnect()
        sbar.rangeChanged.disconnect()

        sbar = self.verticalScrollBar()
        sbar.valueChanged.disconnect()
        #sbar.sliderMoved.disconnect()
        sbar.rangeChanged.disconnect()

    # ------------------------------------------------------------------

    @property
    def handDragging(self):
        """Hand dragging state (*bool*)"""
        return self._handDrag

    @property
    def scrollState(self):
        """Tuple of percentage of scene extents
        *(sceneWidthPercent, sceneHeightPercent)*"""
        centerPoint = self.mapToScene(self.viewport().width()/2,
                                      self.viewport().height()/2)
        sceneRect = self.sceneRect()
        centerWidth = centerPoint.x() - sceneRect.left()
        centerHeight = centerPoint.y() - sceneRect.top()
        sceneWidth =  sceneRect.width()
        sceneHeight = sceneRect.height()

        sceneWidthPercent = centerWidth / sceneWidth if sceneWidth != 0 else 0
        sceneHeightPercent = centerHeight / sceneHeight if sceneHeight != 0 else 0
        return (sceneWidthPercent, sceneHeightPercent)

    @scrollState.setter
    def scrollState(self, state):
        sceneWidthPercent, sceneHeightPercent = state
        x = (sceneWidthPercent * self.sceneRect().width() +
             self.sceneRect().left())
        y = (sceneHeightPercent * self.sceneRect().height() +
             self.sceneRect().top())
        self.centerOn(x, y)

    @property
    def zoomFactor(self):
        """Zoom scale factor (*float*)."""
        return self.transform().m11()

    @zoomFactor.setter
    def zoomFactor(self, newZoomFactor):
        newZoomFactor = newZoomFactor / self.zoomFactor
        self.scale(newZoomFactor, newZoomFactor)

    # ------------------------------------------------------------------

    def wheelEvent(self, wheelEvent):
        """Overrides the wheelEvent to handle zooming.

        :param QWheelEvent wheelEvent: instance of |QWheelEvent|"""
        assert isinstance(wheelEvent, QtGui.QWheelEvent)
        print wheelEvent
        if wheelEvent.modifiers() & QtCore.Qt.ControlModifier:
            self.wheelNotches.emit(wheelEvent.delta() / 240.0)
            wheelEvent.accept()
        else:
            super(ScrollZoomGraphicsView, self).wheelEvent(wheelEvent)

    def keyReleaseEvent(self, keyEvent):
        """Overrides to make sure key release passed on to other classes.

        :param QKeyEvent keyEvent: instance of |QKeyEvent|"""
        assert isinstance(keyEvent, QtGui.QKeyEvent)
        #print("graphicsView keyRelease count=%d, autoRepeat=%s" %
              #(keyEvent.count(), keyEvent.isAutoRepeat()))
        keyEvent.ignore()
        #super(ScrollZoomGraphicsView, self).keyReleaseEvent(keyEvent)

    # ------------------------------------------------------------------

    def checkTransformChanged(self):
        """Return True if view transform has changed.

        Overkill. For current implementation really only need to check
        if ``m11()`` has changed.

        :rtype: bool"""
        delta = 0.001
        result = False

        def different(t, u):
            if u == 0.0:
                d = abs(t - u)
            else:
                d = abs((t - u) / u)
            return d > delta

        t = self.transform()
        u = self._transform

        if False:
            print("t = ")
            self.dumpTransform(t, "    ")
            print("u = ")
            self.dumpTransform(u, "    ")
            print("")

        if (different(t.m11(), u.m11()) or
            different(t.m22(), u.m22()) or
            different(t.m12(), u.m12()) or
            different(t.m21(), u.m21()) or
            different(t.m31(), u.m31()) or
            different(t.m32(), u.m32())):
            self._transform = t
            self.transformChanged.emit()
            result = True
        return result

    def clearTransformChanges(self):
        """Reset view transform changed info."""
        self._transform = self.transform()

    def scrollToTop(self):
        """Scroll view to top."""
        sbar = self.verticalScrollBar()
        sbar.setValue(sbar.minimum())

    def scrollToBottom(self):
        """Scroll view to bottom."""
        sbar = self.verticalScrollBar()
        sbar.setValue(sbar.maximum())

    def scrollToBegin(self):
        """Scroll view to left edge."""
        sbar = self.horizontalScrollBar()
        sbar.setValue(sbar.minimum())

    def scrollToEnd(self):
        """Scroll view to right edge."""
        sbar = self.horizontalScrollBar()
        sbar.setValue(sbar.maximum())

    def centerView(self):
        """Center view."""
        sbar = self.verticalScrollBar()
        sbar.setValue((sbar.maximum() + sbar.minimum())/2)
        sbar = self.horizontalScrollBar()
        sbar.setValue((sbar.maximum() + sbar.minimum())/2)

    def enableScrollBars(self, enable):
        """Set visiblility of the view's scrollbars.

        :param bool enable: True to enable the scrollbars """
        if enable:
            self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
            self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        else:
            self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
            self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

    def enableHandDrag(self, enable):
        """Set whether dragging the view with the hand cursor is allowed.

        :param bool enable: True to enable hand dragging """
        if enable:
            if not self._handDrag:
                self._handDrag = True
                self.setDragMode(QtGui.QGraphicsView.ScrollHandDrag)
        else:
            if self._handDrag:
                self._handDrag = False
                self.setDragMode(QtGui.QGraphicsView.NoDrag)

    # ------------------------------------------------------------------

    def dumpTransform(self, t, padding=""):
        """Dump the transform t to stdout.

        :param t: the transform to dump
        :param str padding: each line is preceded by padding"""
        print("%s%5.3f %5.3f %5.3f" % (padding, t.m11(), t.m12(), t.m13()))
        print("%s%5.3f %5.3f %5.3f" % (padding, t.m21(), t.m22(), t.m23()))
        print("%s%5.3f %5.3f %5.3f" % (padding, t.m31(), t.m32(), t.m33()))

## This function creates an an object that holds the canvas view
class CanvasContainer(QtGui.QFrame):
    
    ## Constructor
    def __init__(self, width, height, includeFirstLayer=True, parent=None, flags=0):
        QtGui.QFrame.__init__(self, parent)
        
        ## Canvas Width
        # @var width
        self.width=width
        
        ## Canvas Height
        # @var height
        self.height=height
        
        ## The scene for this canvas
        # @var scene QGraphicsScene
        self.scene=QtGui.QGraphicsScene()
        
        ## The main For this canvas.
        # @var view QGraphicsView
        self.view=ScrollZoomGraphicsView(self.scene)
        
        self.zoomFactor=1.25
        
        self.view.setInteractive(False)
        self.view.setTransformationAnchor(QtGui.QGraphicsView.AnchorViewCenter)
        
        ## pass along underlying signals
        self.connect(self.scene, QtCore.SIGNAL("changed(const QList<QRectF> &)"), self.sceneChanged)
        self.connect(self.view, QtCore.SIGNAL("transformChanged"), )
        
        layout=QtGui.QGridLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.view, 0, 0)
        self.setLayout(layout)
        self.enableScrollBars(True)
        self.view.show()
        
        ## List of QGraphicsPixmapItems
        # Each scene contains at least one layer.
        # @var layers Python list of QGraphicsPixmapItems
        self.layers=[]  
    #__init__

    ## Add a new layer
    # @param firstLayer bool indicating 
    def addLayer(self):
        ## Create widget
        layer
        
        
        
    #addLayer
    
    def __addFirstLayer(self):
        
        pix.fill(QtGui.QColor(255, 255, 255))   ## White layer
        
        self.layer
    
    
    ## Sets the canvas dimensions
    # @param width The canvas width
    # @param height The canvas height
    def setCanvasDimensions(self, width, height):
        self.width=width
        self.height=height
        
        pass
    #setCanvasDimensions
    
    ## Returns the canvas dimensions
    # @return (width, height)
    def getCanvasDimensions(self):
        return (self.width, self.height)
    #getCanvasDimensions
#CanvasContainer

if __name__=="__main__":
    import BasicTools
    qapp=QtGui.QApplication([])
##    c=CanvasContainer(400, 300)
##    c.show()
#    layer=PaintArea(500, 500, None)
####    undoStack=QtGui.QUndoStack(layer)
####    undoView=QtGui.QUndoView()
####    undoView.setWindowTitle("Undo")
####    
#    layer.setImage(QtGui.QImage("C:/Toolkits/image.png"))
#    
#    
###    layer.show()
####    undoView.show()
###    interface=BasicTools.BasicToolsPlugin()
###    layer.setBrush(interface, "Rectangle")
###    layer.setBrushWidth(3)
###    layer.setBrushColor(QtGui.QColor(255, 0, 0))
#    
#    s=QtGui.QGraphicsScene()
#    s.setBackgroundBrush(QtCore.Qt.gray)
#    s.setSceneRect(0, 0, 500, 500)
#    p=QPen()
#    p.setColor(QtCore.Qt.red)
#    p.setWidth(5)
#    r=s.addRect(10, 10, 50, 60, p)
#    r.setZValue(0)
#    v=ScrollZoomGraphicsView(s)
#    
#    
#    r=s.addRect(50, 60, 70, 100, p)
#    pw=s.addWidget(layer)
#    pw.setZValue(100)
#    pa=QPainter()
#    pa.begin(layer.getImage())
#    styleoption=QtGui.QStyleOptionGraphicsItem()
#    r.paint(pa, styleoption)
#    pa.end()
#    
#    
#    theImage=layer.getImage()
#    theImage.save("C:/Toolkits/image2.png")
    
    s=Canvas()
    s.setSceneRect(0, 0, 500, 500)
    s.setPenColor(QColor(0, 0, 255, 255))
    
    s.setPenWidth(10)
    s.setBrushColor(QColor(123, 255, 0, 0))
    
    s.addLayer()
    s.layers[0].fillImage(QColor(128, 128, 128, 255))
    s.addLayer()
    s.layers[1].fillImage(QColor(128, 255, 128, 128))
    e=QGraphicsEllipseItem(50, 50, 150, 125)
    tempPen=QPen()
    tempPen.setColor(QtCore.Qt.red)
    tempPen.setWidth(6)
#    tempPen.setStyle(QtCore.Qt.DashDotDotLine)
    
    e.setPen(tempPen)
    s.layers[-1].addItem(e)
    
    
    s.setCurrentLayer(1)
    v=ScrollZoomGraphicsView(s)
    v.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
    v.setBackgroundBrush(QtGui.QBrush("gray"))
    v.show()
    qapp.exec_()
    
    
